﻿#ifndef LENSMANAGER_H
#define LENSMANAGER_H
#include <QObject>
#include <QSettings>
#include <QFont>
#include <QPen>
#include "../Nosepiece_global.h"
namespace Qly {

const int MAX_LENS = 10;
enum LENS {LENS_NULL, LENS_1X, LENS_2X, LENS_2_5X, LENS_4X, LENS_5X, LENS_10X, LENS_20X, LENS_40X, LENS_50X, LENS_80X, LENS_100X, LENS_150X};

/**
 * @brief LensData class 辅助类，保存和物镜相关的参数
 * 包括工作距离，数值孔径，当前相机下每个像素的尺寸
 * 还有图像上显示的标尺的长度。
 */
struct NOSEPIECE_EXPORT LensData
{
    enum LENS lens;
    QString displayName; // 当前放大倍数对应的名称，可以为 “5x”、“10x” 这样简单的名字或者 “红外物镜 20x” 这样复杂的名字。
    QString rulerText; //当前 ruler 上显示的文字。比如 “100um”， 或者 “10x 100um”。
    QString comment; // 备注信息，这个在界面上是不显示的。可以写一些这个物镜的一些无需显示出来的信息。比如 “2022/12/5 日更换”。
    double numericalAperture = 0.5; //数值孔径，如果光源控制器是程序控制的，根据这个参数可以自动调整照明光源亮度。
    double pixelSize_um = 1.0; //当前相机下每个像素的尺寸，单位是 um
    double rulerLength_um = 200.0; //图像上标尺的长度，单位是 um
    double xCompensate_um = 0.0; // 切换物镜时的调整量，确保物镜中心位置不变，单位 um。对应电动物镜转盘和电动平台场景。如果没有电动平台，可以简单的设置为 0。
    double yCompensate_um = 0.0; // 切换物镜时的调整量，确保物镜中心位置不变，单位 um。对应电动物镜转盘和电动平台场景。如果没有电动平台，可以简单的设置为 0。
    double workDistance_um = 0.0; // 工作距离，这个距离通常是相对值。以最高放大倍数物镜对焦清晰为原点。这个值反应的是物镜切换时镜头需要上下调整的量。电动 Z 轴时可用这个信息。
};

/**
 * @brief The LensManager class  这个类统一收集了关于物镜的各种信息。物镜切换时，也是这个类统一向其他的类分发消息。
 *                               这个类是单例模式，整个软件中，只有一个实例。
 *                               TODO：如果系统中有多套光路，比如上下两个显微镜，那个这个类需要做修改。
 */
class NOSEPIECE_EXPORT LensManager : public QObject
{
    Q_OBJECT
public:
    explicit LensManager() {}
    /**
     * @brief setLensCount 设置当前系统有几颗物镜
     * @param n 物镜的数量，不能超过 MAX_LENS
     */
    void setLensCount(int n);


    /// 标尺相关的函数
    void setRulerPosition(int x_pix, int y_pix);
    void setRulerLineWidth(int w) {m_rulerLineWidth = w;}
    void setRulerFontSize(int s){m_rulerFontSize = s;}
    void setRulerColor(Qt::GlobalColor color){m_rulerColor = color;}

    QPoint rulerPosition();
    int rulerLineWidth() {return  m_rulerLineWidth;}
    int rulerFontSize() {return m_rulerFontSize;}
    Qt::GlobalColor rulerColor() {return m_rulerColor;}

    int lensCount() {return m_lensCount;}
    void loadSettings(QSettings &settings);
    void writeSettings(QSettings &settings) const;

    /**
     * @brief currentLens 获得当前物镜的信息
     * @return 返回当前物镜信息的引用
     */
    LensData& currentLens();

    /**
     * @brief currentLensIndex 获得当前物镜的 Index。
     * @return  获得当前是第几颗物镜，Index 从 0 开始。
     */
    int currentLensIndex() const;

    /**
     * @brief setLensByIndex 设置第 Index 颗物镜的数据。
     * @param index 物镜的 Index
     * @param d 物镜的数据。
     */
    void setLensByIndex(int index, LensData d);

    /**
     * @brief lensByIndex 获得第 Index 颗物镜的数据。
     * @param Index 物镜的 Index
     * @return 第 Index 颗物镜的数据的引用。
     */
    LensData& lensByIndex(int Index);

    /**
     * @brief lensName 当前物镜名字
     * @return 返回当前物镜的 displayName。
     */
    QString lensName() const;

    /**
     * @brief pixelSize 返回像素尺寸。用于标尺和图像上测量等用途。
     * @return 返回每个像素对应的尺寸，单位是 um
     */
    double pixelSize_um() const;
public slots:
    /**
     * @brief setLens 设置当前的物镜。对于 5 孔物镜转盘来说， index 为 0、1、2、3、4。
     * @param oldlensIndex  切换物镜前的物镜序号，如果不知道，则设为 -1。
     * @param newlensIndex 新的物镜的序号。从 0 开始，最低的倍数为 0。
     */
    void setLens(int oldlensIndex, int newlensIndex);
signals:
    /**
     * @brief lensChanged 切换物镜时会发出这个信号。通知其他部件更新信息。比如 MeasureView 需要更新所有测量的尺寸。电动样品台有可能需要运动一下补偿物镜中心的位置。
     * @param oldlensIndex 切换物镜前的物镜序号，如果不知道，则设为 -1。
     * @param newlensIndex 新的物镜的序号。从 0 开始，最低的倍数为 0。
     */
    void lensChanged(int oldlensIndex, int newlensIndex);
private:

//    Q_DISABLE_COPY(LensManager)
//    Q_DISABLE_MOVE(LensManager)
    int m_lensCount = MAX_LENS;
    int m_curLens = 0;
    LensData m_lens[MAX_LENS]; // TODO：后面这里应该改成可以支持任意多的倍率
    int m_rulerX_pix = 200;
    int m_rulerY_pix = 200;
    Qt::GlobalColor  m_rulerColor;
    int m_rulerLineWidth = 2;
    int m_rulerFontSize = 28;

};


}


#endif // LENSMANAGER_H
